package com.purchasing.system.service.impl;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import com.purchasing.system.exception.ResourceNotFoundException;
import com.purchasing.system.model.Notification;
import com.purchasing.system.model.PurchaseRequest;
import com.purchasing.system.model.User;
import com.purchasing.system.payload.request.PurchaseRequestDto;
import com.purchasing.system.repository.PurchaseRequestRepository;
import com.purchasing.system.repository.UserRepository;
import com.purchasing.system.service.NotificationService;
import com.purchasing.system.service.PurchaseRequestService;
import javax.persistence.criteria.Predicate;

@Service
public class PurchaseRequestServiceImpl implements PurchaseRequestService {
    
    @Autowired
    private PurchaseRequestRepository purchaseRequestRepository;
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private NotificationService notificationService;
    
    @Value("${file.upload-dir}")
    private String uploadDir;

//    验证用户存在：
//    通过 userId 查找对应的 User 实体，确保用户存在。如果不存在，抛出异常。
//            创建采购申请实体：
//    根据 purchaseRequestDto 中的数据，创建一个新的 PurchaseRequest 实体，并设置相关属性（如物品名称、数量、预算、原因等）。
//    设置采购申请的状态为“待审批”（PENDING）。
//    关联当前用户作为申请人，并记录创建时间。
//            处理附件上传（如果有）：
//    如果用户上传了附件，调用 saveAttachment 方法将附件保存到服务器的指定目录，并将保存后的文件名设置到 PurchaseRequest 实体的 attachmentPath 属性中。
//            保存采购申请到数据库：
//    使用 purchaseRequestRepository.save(purchaseRequest) 将 PurchaseRequest 实体持久化到数据库，生成唯一的 id。
//            发送通知：
//    向所有管理员发送通知，告知有新的采购申请需要审批。
//    向申请人发送系统通知，确认其采购申请已成功提交并处于待审批状态。
//            返回保存后的采购申请实体：
//    将保存后的 PurchaseRequest 实体返回给调用方，便于前端展示或进一步处理。
    @Override
    //表示该方法重写了 PurchaseRequestService 接口中的同名方法
    @Transactional
    //表示该方法在一个数据库事务中执行。如果在方法执行过程中发生任何异常，所有的数据库操作将会回滚，确保数据的一致性。
    public PurchaseRequest createPurchaseRequest(PurchaseRequestDto purchaseRequestDto, MultipartFile attachment, Long userId) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + userId));
        
        PurchaseRequest purchaseRequest = new PurchaseRequest();//实例化一个新的 PurchaseRequest 对象，用于存储本次采购申请的信息。
        purchaseRequest.setItemName(purchaseRequestDto.getItemName());
        purchaseRequest.setQuantity(purchaseRequestDto.getQuantity());
        purchaseRequest.setBudget(purchaseRequestDto.getBudget());
        purchaseRequest.setReason(purchaseRequestDto.getReason());
        purchaseRequest.setStatus(PurchaseRequest.PurchaseStatus.PENDING);
        purchaseRequest.setRequestUser(user);
        purchaseRequest.setCreatedAt(LocalDateTime.now());
        
        // 处理附件上传
        if (attachment != null && !attachment.isEmpty()) {
            String attachmentPath = saveAttachment(attachment);//调用 saveAttachment 方法，将上传的附件文件保存到服务器的指定目录，并返回保存后的文件名
            purchaseRequest.setAttachmentPath(attachmentPath);
        }
        
        PurchaseRequest savedRequest = purchaseRequestRepository.save(purchaseRequest);//使用 Spring Data JPA 的 save 方法，将 purchaseRequest 实体持久化到数据库中。

        // 发送通知给所有管理员
        notificationService.sendNotificationToAdmins(
                "新的采购申请待审批",
                "有一个新的采购申请需要审批，申请物品：" + purchaseRequest.getItemName(),
                Notification.NotificationType.APPROVAL_REQUIRED,
                savedRequest.getId()
        );
        
        // 发送系统通知给申请人
        notificationService.sendNotification(
                userId,
                "采购申请已提交",
                "您的" + purchaseRequest.getItemName() + "采购申请已成功提交，等待审批",
                Notification.NotificationType.SYSTEM_MESSAGE,
                savedRequest.getId()
        );
        
        return savedRequest;
    }

    @Override
    public Page<PurchaseRequest> getPurchaseRequestsByUser(Long userId, Pageable pageable) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + userId));
        
        return purchaseRequestRepository.findByRequestUser(user, pageable);
    }

    @Override
    public Page<PurchaseRequest> getPurchaseRequestsByUserAndStatus(Long userId, PurchaseRequest.PurchaseStatus status, Pageable pageable) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + userId));
        
        return purchaseRequestRepository.findByRequestUserAndStatus(user, status, pageable);
    }

    @Override
    public Page<PurchaseRequest> getPendingPurchaseRequests(Pageable pageable) {
        return purchaseRequestRepository.findByStatus(PurchaseRequest.PurchaseStatus.PENDING, pageable);
    }

    @Override
    public Page<PurchaseRequest> getPurchaseRequestsByStatus(PurchaseRequest.PurchaseStatus status, Pageable pageable) {
        return purchaseRequestRepository.findByStatus(status, pageable);
    }

    @Override
    public Page<PurchaseRequest> getAllPurchaseRequests(Pageable pageable) {
        return purchaseRequestRepository.findAll(pageable);
    }

    @Override
    public Page<PurchaseRequest> searchPurchaseRequests(String keyword, Pageable pageable) {
        return purchaseRequestRepository.findByRequestUserNameContaining(keyword, pageable);
    }

    @Override
    public Page<PurchaseRequest> getApprovedPurchaseRequests(Pageable pageable) {
        return purchaseRequestRepository.findByStatusNot(PurchaseRequest.PurchaseStatus.PENDING, pageable);
    }

    @Override
    public PurchaseRequest getPurchaseRequestById(Long id, Long userId) {
        PurchaseRequest purchaseRequest = purchaseRequestRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Purchase request not found with id: " + id));
        
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + userId));
        
        // 检查权限：只有管理员或者申请人自己可以查看
        if (!isAdminUser(user) && !purchaseRequest.getRequestUser().getId().equals(userId)) {
            throw new AccessDeniedException("You don't have permission to access this purchase request");
        }
        
        return purchaseRequest;
    }

    @Override
    @Transactional
    public PurchaseRequest updatePurchaseRequest(Long id, PurchaseRequestDto purchaseRequestDto, Long userId) {
        PurchaseRequest purchaseRequest = purchaseRequestRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Purchase request not found with id: " + id));
        
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + userId));
        
        // 检查权限：只有申请人自己可以修改，且只能修改未审批的申请
        if (!purchaseRequest.getRequestUser().getId().equals(userId)) {
            throw new AccessDeniedException("You don't have permission to update this purchase request");
        }
        
        if (purchaseRequest.getStatus() != PurchaseRequest.PurchaseStatus.PENDING) {
            throw new IllegalStateException("Cannot update a purchase request that has been approved or rejected");
        }
        
        purchaseRequest.setItemName(purchaseRequestDto.getItemName());
        purchaseRequest.setQuantity(purchaseRequestDto.getQuantity());
        purchaseRequest.setBudget(purchaseRequestDto.getBudget());
        purchaseRequest.setReason(purchaseRequestDto.getReason());
        purchaseRequest.setUpdatedAt(LocalDateTime.now());
        
        return purchaseRequestRepository.save(purchaseRequest);
    }

    @Override
    @Transactional
    public PurchaseRequest updatePurchaseRequest(Long id, PurchaseRequestDto purchaseRequestDto, MultipartFile attachment, Long userId) {
        PurchaseRequest purchaseRequest = purchaseRequestRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Purchase request not found with id: " + id));
        
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + userId));
        
        // 检查权限：只有申请人自己可以修改，且只能修改未审批的申请
        if (!purchaseRequest.getRequestUser().getId().equals(userId)) {
            throw new AccessDeniedException("You don't have permission to update this purchase request");
        }
        
        if (purchaseRequest.getStatus() != PurchaseRequest.PurchaseStatus.PENDING) {
            throw new IllegalStateException("Cannot update a purchase request that has been approved or rejected");
        }
        
        purchaseRequest.setItemName(purchaseRequestDto.getItemName());
        purchaseRequest.setQuantity(purchaseRequestDto.getQuantity());
        purchaseRequest.setBudget(purchaseRequestDto.getBudget());
        purchaseRequest.setReason(purchaseRequestDto.getReason());
        purchaseRequest.setUpdatedAt(LocalDateTime.now());
        
        // 处理附件上传
        if (attachment != null && !attachment.isEmpty()) {
            String attachmentPath = saveAttachment(attachment);
            purchaseRequest.setAttachmentPath(attachmentPath);
        }
        
        return purchaseRequestRepository.save(purchaseRequest);
    }

    @Override
    @Transactional
    public void deletePurchaseRequest(Long id, Long userId) {
        PurchaseRequest purchaseRequest = purchaseRequestRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Purchase request not found with id: " + id));
        
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + userId));
        
        // 检查权限：只有申请人自己可以删除，且只能删除未审批的申请
        if (!purchaseRequest.getRequestUser().getId().equals(userId)) {
            throw new AccessDeniedException("You don't have permission to delete this purchase request");
        }
        
        if (purchaseRequest.getStatus() != PurchaseRequest.PurchaseStatus.PENDING) {
            throw new IllegalStateException("Cannot delete a purchase request that has been approved or rejected");
        }
        
        purchaseRequestRepository.delete(purchaseRequest);
    }

    @Override
    @Transactional
    public PurchaseRequest approvePurchaseRequest(Long id, boolean approved, String comment, Long approverId) {
        PurchaseRequest purchaseRequest = purchaseRequestRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Purchase request not found with id: " + id));
        
        User approver = userRepository.findById(approverId)
                .orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + approverId));
        
        // 检查权限：只有管理员可以审批
        if (!isAdminUser(approver)) {
            throw new AccessDeniedException("You don't have permission to approve purchase requests");
        }
        
        // 检查状态：只能审批待审批的申请
        if (purchaseRequest.getStatus() != PurchaseRequest.PurchaseStatus.PENDING) {
            throw new IllegalStateException("This purchase request has already been processed");
        }
        
        // 更新审批状态
        purchaseRequest.setStatus(approved ? PurchaseRequest.PurchaseStatus.APPROVED : PurchaseRequest.PurchaseStatus.REJECTED);
        purchaseRequest.setApprovalComment(comment);
        purchaseRequest.setApprover(approver);
        purchaseRequest.setApprovalDate(LocalDateTime.now());
        purchaseRequest.setUpdatedAt(LocalDateTime.now());
        
        PurchaseRequest updatedRequest = purchaseRequestRepository.save(purchaseRequest);
        
        // 发送通知给申请人
        String title = approved ? "您的采购申请已通过" : "您的采购申请被拒绝";
        String content = "您申请采购的物品 " + purchaseRequest.getItemName() + " " +
                (approved ? "已通过审批" : "未通过审批") + 
                (StringUtils.hasText(comment) ? "，审批意见：" + comment : "");
        
        notificationService.sendNotification(
                purchaseRequest.getRequestUser().getId(),
                title,
                content,
                Notification.NotificationType.APPROVAL_RESULT,
                updatedRequest.getId()
        );
        
        return updatedRequest;
    }
    
    private String saveAttachment(MultipartFile file) {
        try {
            // 创建上传目录（如果不存在）
            Path uploadPath = Paths.get(uploadDir);
            if (!Files.exists(uploadPath)) {
                Files.createDirectories(uploadPath);
            }
            
            // 生成唯一文件名
            String originalFilename = StringUtils.cleanPath(file.getOriginalFilename());
            String fileExtension = "";
            if (originalFilename.contains(".")) {
                fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
            }
            String filename = UUID.randomUUID().toString() + fileExtension;
            
            // 保存文件
            Path filePath = uploadPath.resolve(filename);
            Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
            
            return filename;
        } catch (IOException e) {
            throw new RuntimeException("Failed to save attachment", e);
        }
    }
    
    private boolean isAdminUser(User user) {
        return user.getRoles().stream()
                .anyMatch(role -> role.getName().name().equals("ROLE_ADMIN"));
    }

    @Override
    public Page<PurchaseRequest> getPendingPurchaseRequestsByItemName(String itemName, Pageable pageable) {
        return purchaseRequestRepository.findPendingByItemNameContaining(itemName, pageable);
    }

    @Override
    public Page<PurchaseRequest> getPendingPurchaseRequestsByRequesterName(String requesterName, Pageable pageable) {
        System.out.println("搜索申请人: " + requesterName);
        Page<PurchaseRequest> results = purchaseRequestRepository.findPendingByRequesterNameContaining(requesterName, pageable);
        System.out.println("找到结果数量: " + results.getTotalElements());
        return results;
    }

    @Override
    public Page<PurchaseRequest> getPurchaseRequestsByUserAndDateRange(Long userId, LocalDateTime startDate, LocalDateTime endDate, Pageable pageable) {
        return purchaseRequestRepository.findByRequestUserIdAndCreatedAtBetween(userId, startDate, endDate, pageable);
    }
    
    @Override
    public Page<PurchaseRequest> getPurchaseRequestsByUserAndStatusAndDateRange(Long userId, PurchaseRequest.PurchaseStatus status, LocalDateTime startDate, LocalDateTime endDate, Pageable pageable) {
        return purchaseRequestRepository.findByRequestUserIdAndStatusAndCreatedAtBetween(userId, status, startDate, endDate, pageable);
    }
    
    @Override
    public Page<PurchaseRequest> searchUserPurchaseRequestsByItemName(Long userId, String itemName, String status, LocalDateTime startDate, LocalDateTime endDate, Pageable pageable) {
        if (itemName == null || itemName.isEmpty()) {
            return new PageImpl<>(Collections.emptyList(), pageable, 0);
        }
        
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + userId));
        
        // 基本的按物品名称查询
        if (status == null && startDate == null && endDate == null) {
            return purchaseRequestRepository.findByRequestUserIdAndItemNameContaining(userId, itemName, pageable);
        }
        
        // 复杂条件查询，使用自定义条件
        Specification<PurchaseRequest> spec = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            // 用户条件
            predicates.add(cb.equal(root.get("requestUser").get("id"), userId));
            
            // 物品名称条件
            predicates.add(cb.like(root.get("itemName"), "%" + itemName + "%"));
            
            // 状态条件
            if (status != null && !status.isEmpty()) {
                predicates.add(cb.equal(root.get("status"), 
                        PurchaseRequest.PurchaseStatus.valueOf(status.toUpperCase())));
            }
            
            // 日期范围条件
            if (startDate != null && endDate != null) {
                predicates.add(cb.between(root.get("createdAt"), startDate, endDate));
            } else if (startDate != null) {
                predicates.add(cb.greaterThanOrEqualTo(root.get("createdAt"), startDate));
            } else if (endDate != null) {
                predicates.add(cb.lessThanOrEqualTo(root.get("createdAt"), endDate));
            }
            
            return cb.and(predicates.toArray(new Predicate[0]));
        };
        
        return purchaseRequestRepository.findAll(spec, pageable);
    }

    @Override
    public Page<PurchaseRequest> searchPurchaseRequestsByItemName(String itemName, Pageable pageable) {
        if (itemName == null || itemName.isEmpty()) {
            return new PageImpl<>(Collections.emptyList(), pageable, 0);
        }
        
        return purchaseRequestRepository.findAll(
            (root, query, cb) -> cb.like(root.get("itemName"), "%" + itemName + "%"),
            pageable
        );
    }
    
    @Override
    public Page<PurchaseRequest> searchPurchaseRequestsByRequesterName(String requesterName, Pageable pageable) {
        if (requesterName == null || requesterName.isEmpty()) {
            return new PageImpl<>(Collections.emptyList(), pageable, 0);
        }
        
        return purchaseRequestRepository.findAll(
            (root, query, cb) -> cb.or(
                cb.like(root.get("requestUser").get("name"), "%" + requesterName + "%"),
                cb.like(root.get("requestUser").get("username"), "%" + requesterName + "%")
            ),
            pageable
        );
    }

    @Override
    public Page<PurchaseRequest> findAll(Specification<PurchaseRequest> spec, Pageable pageable) {
        return purchaseRequestRepository.findAll(spec, pageable);
    }
} 